package hamaster.jpbc.pbc.io;

import it.unisa.dia.gas.jpbc.Element;
import hamaster.jpbc.pbc.CipherText;
import hamaster.jpbc.pbc.PBC;
import hamaster.jpbc.pbc.PlainText;
import hamaster.jpbc.pbc.PrivateKey;
import hamaster.jpbc.pbc.PublicParameter;
import hamaster.jpbc.pbs.PersonalParameter;

public class ID {
	private static final int ZR_SIZE = 20;
	private static final int GS_SIZE = 128;

	protected PersonalParameter personalParameter;
	protected PublicParameter publicParameter;
	protected PrivateKey privateKey;

	/**
	 * 加密后的签名私钥
	 */
	private Element alphaU;
	private Element alphaV;
	private Element alphaW;

	public ID() {
	}

	public PersonalParameter getPersonalParameter() {
		return personalParameter;
	}

	public void setPersonalParameter(PersonalParameter personalParameter) {
		this.personalParameter = personalParameter;
	}

	public PublicParameter getPublicParameter() {
		return publicParameter;
	}

	public void setPublicParameter(PublicParameter publicParameter) {
		this.publicParameter = publicParameter;
	}

	public PrivateKey getPrivateKey() {
		return privateKey;
	}

	public void setPrivateKey(PrivateKey privateKey) {
		this.privateKey = privateKey;
	}

	public boolean setSignatureKey(Element alpha) {
		if (privateKey == null || publicParameter == null)
			return false;
		PlainText p = new PlainText();
		Element gtElement = PBC.instance().getPairing().getGT().newElement();
		byte[] buffer = new byte[GS_SIZE];
		byte[] abytes = alpha.toBytes();
		//多余字节用0填充
//		System.arraycopy(abytes, 0, buffer, GS_SIZE - abytes.length, abytes.length);
		System.arraycopy(abytes, 0, buffer, 0, abytes.length);
		gtElement.setFromBytes(buffer);
		p.setElement(gtElement);
		CipherText c = PBC.instance().encrypt(p, personalParameter.getUser(), publicParameter);
		alphaU = c.getU();
		alphaV = c.getV();
		alphaW = c.getW();
		return true;
	}

	public Element getSignatureKey() {
		if (alphaU == null || alphaV == null || alphaW == null)
			return null;
		CipherText c = new CipherText();
		c.setU(alphaU);
		c.setV(alphaV);
		c.setW(alphaW);
		PBC pbc = PBC.instance();
		PlainText p = pbc.decrypt(c, privateKey);
		Element gt = p.getElement();
		byte[] gbytes = gt.toBytes();
		byte[] buffer = new byte[ZR_SIZE];
		//只拷贝20字节
		System.arraycopy(gbytes, 0, buffer, 0, ZR_SIZE);
		Element zr = pbc.getPairing().getZr().newElement();
		zr.setFromBytes(buffer);
		return zr;
	}

	public Element getAlphaU() {
		return alphaU;
	}

	public void setAlphaU(Element alphaU) {
		this.alphaU = alphaU;
	}

	public Element getAlphaV() {
		return alphaV;
	}

	public void setAlphaV(Element alphaV) {
		this.alphaV = alphaV;
	}

	public Element getAlphaW() {
		return alphaW;
	}

	public void setAlphaW(Element alphaW) {
		this.alphaW = alphaW;
	}

	@Override
	public String toString() {
		return "[ID]\n" + personalParameter
				+ "\n" + publicParameter + "\n"
				+ privateKey + "\nalphaU=" + alphaU + "\nalphaV=" + alphaV
				+ "\nalphaW=" + alphaW;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ID other = (ID) obj;
		if (alphaU == null) {
			if (other.alphaU != null)
				return false;
		} else if (!alphaU.equals(other.alphaU))
			return false;
		if (alphaV == null) {
			if (other.alphaV != null)
				return false;
		} else if (!alphaV.equals(other.alphaV))
			return false;
		if (alphaW == null) {
			if (other.alphaW != null)
				return false;
		} else if (!alphaW.equals(other.alphaW))
			return false;
		if (personalParameter == null) {
			if (other.personalParameter != null)
				return false;
		} else if (!personalParameter.equals(other.personalParameter))
			return false;
		if (privateKey == null) {
			if (other.privateKey != null)
				return false;
		} else if (!privateKey.equals(other.privateKey))
			return false;
		if (publicParameter == null) {
			if (other.publicParameter != null)
				return false;
		} else if (!publicParameter.equals(other.publicParameter))
			return false;
		return true;
	}

	@Override
	protected void finalize() throws Throwable {
		alphaU.setToRandom();
		alphaV.setToRandom();
		alphaW.setToRandom();
		super.finalize();
	}

}
